home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 19 / develop 19 code / Adding GX Printing to QD Apps / Simple Sample GX ƒ / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-10  |  20.4 KB  |  773 lines  |  [TEXT/KAHL]

  1. /*********************************************************************
  2.  
  3.     files.c
  4.     
  5.     This file contains the file I/O code for the QuickDraw GX aware
  6.     sample, "Simple Sample GX."
  7.     
  8.     Additional info can be found in the related develop #19 article,
  9.     "Adding QuickDraw GX Printing to QuickDraw Applications."
  10.  
  11.     Dave Hersey, Apple Developer Technical Support.
  12.     
  13.     ——————— Edit Trail ———————
  14.     
  15.     hatched:                                        1/22/94  - dmh
  16.     cleaned up for 2nd draft of develop article:    3/10/94  - dmh
  17.     cleaned up for final:                            4/14/94  - dmh
  18.     
  19. *********************************************************************/
  20.  
  21. #include "Simple Sample.h"
  22.  
  23.  
  24. /************************************************************
  25.   MyLoadDocument - This routine loads a previously saved
  26.   document.
  27.  
  28. *************************************************************/
  29.  
  30. OSErr MyLoadDocument(MyDocumentPtr whichDocument)
  31. {
  32.     OSErr                err;
  33.     short                oldResFile, dataRefNum = -1, resRefNum = -1;
  34.     StandardFileReply    sfReply;
  35.     SFTypeList            myTypeList;
  36.     WindowPtr            curWindow;
  37.     MyDocumentPtr        windDoc;
  38.     Boolean                notAlreadyOpen;
  39.  
  40. // Let the user select a document to open.
  41.  
  42.     myTypeList[0] = kMyDocType;
  43.     StandardGetFile(nil, 1, myTypeList, &sfReply);
  44.     require_action(sfReply.sfGood, UserHasCancelled, err = iPrAbort;);
  45.  
  46. /*
  47.     Make sure that we haven't already opened this document. If
  48.     we have, just bring the old window forward.
  49. */
  50.     nrequire_action(MyIsWindowAlreadyOpen(&sfReply.sfFile),
  51.                     DocIsAlreadyOpen, err = iPrAbort;);
  52.  
  53. // Open the selected file's data fork and resource fork.
  54.  
  55.     err = FSpOpenDF(&sfReply.sfFile, fsRdWrPerm, &dataRefNum);
  56.     nrequire(err, CouldNotOpenDataFork);
  57.  
  58.     resRefNum = HOpenResFile(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  59.                              sfReply.sfFile.name, fsRdPerm);
  60.  
  61.     err = ResError();
  62.     nrequire(err, CouldNotOpenResourceFork);
  63.  
  64. /*
  65.     If we're successful in opening the file, set our document's
  66.     FSSpec info, its title, and its window's title.
  67. */
  68.  
  69.     oldResFile = CurResFile();
  70.     
  71.     BlockMove(&sfReply.sfFile, &whichDocument->documentFSSpec, sizeof(FSSpec));
  72.     BlockMove(&sfReply.sfFile.name, whichDocument->documentTitle,
  73.               (long) sfReply.sfFile.name[0] +1);
  74.     
  75.     SetWTitle(whichDocument->documentWindow, whichDocument->documentTitle);
  76.     err = MyLoadPrintInfo(whichDocument, resRefNum);
  77.  
  78. // Now load the data for our document's pages.
  79.  
  80.     whichDocument->numPages = MyLoadPageCount(resRefNum);
  81.     whichDocument->curPage = 1;
  82.  
  83.     /* 
  84.         Place your application-specific code here to load 
  85.         other data associated with the document.
  86.         .
  87.         .
  88.         .
  89.     */
  90.  
  91.     MyAdjustMenus();
  92.  
  93. // Close the data and resource forks of this document.
  94.  
  95.     UseResFile(oldResFile);
  96.     CloseResFile(resRefNum);
  97.  
  98. CouldNotOpenResourceFork:
  99.     FSClose(dataRefNum);
  100.  
  101. CouldNotOpenDataFork:
  102. DocIsAlreadyOpen:
  103. UserHasCancelled:
  104.     return err;
  105. }
  106.  
  107.  
  108. /************************************************************
  109.   MyFSLoadDocument - This routine opens a document and loads
  110.   its previously saved job, reassociating any formats that
  111.   the job contains.  It's just like MyLoadDocument, but it
  112.   opens the indicated file and doesn't present a file
  113.   dialog.
  114.  
  115. *************************************************************/
  116.  
  117. OSErr MyFSLoadDocument(MyDocumentPtr whichDocument, FSSpec *docFSSpec,
  118.                        Boolean forPrinting)
  119. {
  120.     OSErr        err;
  121.     short        oldResFile, dataRefNum, resRefNum;
  122.  
  123. /*
  124.     Unless we're printing, make sure that we haven't already opened
  125.     this document. If we have, just bring the old window forward.
  126. */
  127.  
  128.     require_action(forPrinting || !MyIsWindowAlreadyOpen(docFSSpec),
  129.                    DocIsAlreadyOpen, err = iPrAbort;);
  130.  
  131. // Open the selected file's data fork and resource fork.
  132.  
  133.     err = FSpOpenDF(docFSSpec, fsRdWrPerm, &dataRefNum);
  134.     nrequire(err, CouldNotOpenDataFork);
  135.  
  136.     resRefNum = HOpenResFile(docFSSpec->vRefNum, docFSSpec->parID, docFSSpec->name, fsRdPerm);
  137.     err = ResError();
  138.     nrequire(err, CouldNotOpenResourceFork);
  139.  
  140. /*
  141.     If we're successful in opening the file, set our document's
  142.     FSSpec info and its window's title.
  143. */
  144.  
  145.     oldResFile = CurResFile();
  146.  
  147.     BlockMove(docFSSpec, &whichDocument->documentFSSpec, sizeof(FSSpec));
  148.     BlockMove(docFSSpec->name, whichDocument->documentTitle, (long) docFSSpec->name[0] +1);
  149.     SetWTitle(whichDocument->documentWindow, whichDocument->documentTitle);
  150.  
  151.     err = MyLoadPrintInfo(whichDocument, resRefNum);
  152.  
  153. // Now load the data for our document's pages.
  154.  
  155.     whichDocument->numPages = MyLoadPageCount(resRefNum);
  156.     whichDocument->curPage = 1;
  157.  
  158.     /* 
  159.         Place your application-specific code here to load 
  160.         other data associated with the document.
  161.         .
  162.         .
  163.         .
  164.     */
  165.  
  166.     MyAdjustMenus();
  167.  
  168. // Close the data and resource forks of this document.
  169.  
  170.     UseResFile(oldResFile);
  171.     CloseResFile(resRefNum);
  172.  
  173. CouldNotOpenResourceFork:
  174.     FSClose(dataRefNum);
  175.  
  176. CouldNotOpenDataFork:
  177. DocIsAlreadyOpen:
  178.     return err;
  179. }
  180.  
  181.  
  182. /************************************************************
  183.   MyIsWindowAlreadyOpen - This routine compares a file spec
  184.   with those for our currently opened documents.  If we find
  185.   a match, we bring that document's window forward and return
  186.   true.  Otherwise, we return false.
  187.  
  188. *************************************************************/
  189.  
  190. Boolean MyIsWindowAlreadyOpen(FSSpec *whichFSSpec)
  191. {
  192.     WindowPtr        curWindow;
  193.     MyDocumentPtr    curDocument;
  194.     Boolean            isAlreadyOpen = false;
  195.  
  196. /*
  197.     Make sure that we haven't already opened this document. If
  198.     we have, just bring the old window forward and adjust our menus.
  199. */
  200.     curWindow = FrontWindow();
  201.     
  202.     while (curWindow != nil)
  203.     {
  204.         if (((WindowPeek) curWindow)->windowKind == userKind)
  205.         {
  206.             curDocument = MyGetDocPtr(curWindow);
  207.             
  208.             isAlreadyOpen =
  209.                 ((curDocument->documentFSSpec.vRefNum == whichFSSpec->vRefNum) &&
  210.                  (curDocument->documentFSSpec.parID == whichFSSpec->parID) &&
  211.                  (IUEqualString(curDocument->documentFSSpec.name, whichFSSpec->name) == 0));
  212.  
  213.             if (isAlreadyOpen)
  214.             {
  215.                 SelectWindow(curWindow);
  216.                 MyAdjustMenus();
  217.             }
  218.             
  219.             nrequire(isAlreadyOpen, DocIsAlreadyOpen);
  220.         }
  221.     
  222.         curWindow = (WindowPtr) ((WindowPeek) curWindow)->nextWindow;
  223.     }
  224.  
  225. DocIsAlreadyOpen:
  226. NoNeedToCheck:
  227.     return isAlreadyOpen;
  228. }
  229.  
  230.  
  231. /************************************************************
  232.   MySaveDocument - This routine saves a document and its
  233.   corresponding job to disk.  It also saves a format
  234.   collection item containing our page-to-format
  235.   correpondences.
  236.  
  237. *************************************************************/
  238.  
  239. OSErr MySaveDocument(MyDocumentPtr whichDocument, Boolean doingSaveAs)
  240. {
  241.     OSErr                err = noErr;
  242.     short                dataRefNum, oldResFile, resRefNum;
  243.     FSSpec                *docFSSpec;
  244.     StandardFileReply    sfReply;
  245.     FInfo                docFInfo;
  246.  
  247.     oldResFile = CurResFile();
  248.     docFSSpec = &whichDocument->documentFSSpec;
  249.  
  250. /*
  251.     If we're doing a "Save as…", display the StandardFile
  252.     dialog and have the user select a place to save the file.
  253. */
  254.  
  255.     if (doingSaveAs)
  256.     {
  257.         StandardPutFile("\pSave document:", whichDocument->documentTitle, &sfReply);
  258.         require(sfReply.sfGood, UserHasCancelled);
  259.  
  260. /*
  261.     If we're replacing an existing file, delete it.  Create
  262.     our new file and set its creator and type.
  263. */
  264.         if (sfReply.sfReplacing)
  265.             err = HDelete(sfReply.sfFile.vRefNum, sfReply.sfFile.parID, sfReply.sfFile.name);
  266.  
  267.         nrequire(err, CouldNotDeleteOldFile);
  268.  
  269.         HCreateResFile(sfReply.sfFile.vRefNum, sfReply.sfFile.parID, sfReply.sfFile.name);
  270.         HGetFInfo(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  271.                   sfReply.sfFile.name, &docFInfo);
  272.               
  273.         docFInfo.fdCreator = kMyDocCreator;
  274.         docFInfo.fdType = kMyDocType;
  275.  
  276.         err = HSetFInfo(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  277.                         sfReply.sfFile.name, &docFInfo);
  278.  
  279. /*
  280.     If we're successful in creating the file, set our document's
  281.     FSSpec info, its title and its window's title.
  282. */
  283.  
  284.         if (err == noErr) err = ResError();
  285.         nrequire(err, CouldNotSetFileInfo);
  286.  
  287.         BlockMove(&sfReply.sfFile, docFSSpec, sizeof(FSSpec));
  288.         BlockMove(&sfReply.sfFile.name, whichDocument->documentTitle,
  289.                   (long) sfReply.sfFile.name[0] +1);
  290.         
  291.         SetWTitle(whichDocument->documentWindow, whichDocument->documentTitle);
  292.     }
  293.  
  294. // Open the file's data fork and resource fork.
  295.  
  296.     err = FSpOpenDF(docFSSpec, fsRdWrPerm, &dataRefNum);
  297.     nrequire(err, CouldNotOpenDataFork);
  298.  
  299.     resRefNum = HOpenResFile(docFSSpec->vRefNum, docFSSpec->parID,
  300.                              docFSSpec->name, fsRdWrPerm);
  301.     err = ResError();
  302.     nrequire(err, CouldNotOpenResourceFork);
  303.  
  304.     err = MySavePrintInfo(whichDocument, resRefNum);
  305.  
  306. // Now save the data for our document's pages.
  307.  
  308.     if (!err)
  309.         err = MySavePageCount(whichDocument, resRefNum);
  310.  
  311.     /* 
  312.         Place your application-specific code here to save 
  313.         other data associated with the document.
  314.         .
  315.         .
  316.         .
  317.     */
  318.  
  319. // Close the data and resource forks of this document.
  320.  
  321.     CloseResFile(resRefNum);
  322.  
  323. CouldNotOpenResourceFork:
  324.     FSClose(dataRefNum);
  325.  
  326. CouldNotOpenDataFork:
  327. CouldNotSetFileInfo:
  328. CouldNotDeleteOldFile:
  329. UserHasCancelled:
  330.     UseResFile(oldResFile);
  331.     return err;
  332. }
  333.  
  334.  
  335. /************************************************************
  336.   MySavePageCount - This routine saves a resource containing
  337.   the number of pages in our document.
  338.  
  339. *************************************************************/
  340.  
  341. OSErr MySavePageCount(MyDocumentPtr whichDocument, short resRefNum)
  342. {
  343.     OSErr        err;
  344.     Handle        thePageCount, oldPageCount;
  345.  
  346.     UseResFile(resRefNum);
  347.  
  348. // If there's an existing resource, delete it.
  349.  
  350.     thePageCount = NewHandle(sizeof(long));
  351.     nrequire((err = MemError()), CouldNotCreateHandle);
  352.  
  353.     *(long *)*thePageCount = whichDocument->numPages;
  354.     oldPageCount = Get1Resource(kMyPageCountType, kMyPageCountID);
  355.  
  356.     if (oldPageCount != nil)
  357.     {
  358.         RmveResource(oldPageCount);
  359.         UpdateResFile(resRefNum);
  360.         DisposHandle(oldPageCount);
  361.     }
  362.  
  363. // Add our new resource.
  364.  
  365.     AddResource(thePageCount, kMyPageCountType, kMyPageCountID, "\p");
  366.     err = ResError();
  367.     nrequire(err, CouldNotAddResource);
  368.  
  369.     WriteResource(thePageCount);
  370.     UpdateResFile(resRefNum);
  371.     ReleaseResource(thePageCount);
  372.  
  373. CouldNotAddResource:
  374. CouldNotCreateHandle:
  375.     return err;
  376. }
  377.  
  378.  
  379. /************************************************************
  380.   MyLoadPageCount - This routine loads a resource containing
  381.   the number of pages in our document, and returns the number
  382.   of pages.
  383.  
  384. *************************************************************/
  385.  
  386. long MyLoadPageCount(short resRefNum)
  387. {
  388.     Handle        thePageCount;
  389.     long        numPages;
  390.  
  391.     UseResFile(resRefNum);
  392.  
  393. // Get the page count.  If we don't find a count, return 1.
  394.  
  395.     thePageCount = Get1Resource(kMyPageCountType, kMyPageCountID);
  396.  
  397.     if (thePageCount != nil)
  398.     {
  399.         numPages = *(long *)*thePageCount;
  400.         ReleaseResource(thePageCount);
  401.     }
  402.     else
  403.         numPages = 1;
  404.  
  405.     return numPages;
  406. }
  407.  
  408.  
  409. /************************************************************
  410.   MySaveFormatRefs - This routine saves page format indices
  411.   for a document.  We'll store this info in the job's
  412.   default format's collection.  We use this information to
  413.   "reconstruct" the document the next time we open it.
  414.   This routine is called when we save a document, before we
  415.   have flattened the document's job.
  416.  
  417. *************************************************************/
  418.  
  419. OSErr MySaveFormatRefs(MyDocumentPtr whichDocument)
  420. {
  421.     OSErr                err = noErr;
  422.     Handle                theFormatIdxList;
  423.     Collection            fmtCollection;
  424.     gxFormat            defaultFmt;
  425.  
  426.     if (whichDocument->numPages > 0)
  427.     {
  428.  
  429. // Get the job's default format's collection.
  430.  
  431.         defaultFmt = GXGetJobFormat(whichDocument->documentJob, 1);
  432.         fmtCollection = GXGetFormatCollection(defaultFmt);
  433.  
  434. /*
  435.     Create a list of page-to-format correspondences for the current
  436.     document.  If there are no errors, add the item to the job's
  437.     default format's collection for later retrieval.
  438. */
  439.         err = MyCreateFormatIndexList(whichDocument, &theFormatIdxList);
  440.  
  441.         if (err == noErr)
  442.         {
  443.             HLock(theFormatIdxList);
  444.             err = AddCollectionItem(fmtCollection,
  445.                                     kMyFormatInfoType,
  446.                                     kMyFormatInfoTagID,
  447.                                     GetHandleSize(theFormatIdxList),
  448.                                     *theFormatIdxList);
  449.     
  450.             DisposHandle(theFormatIdxList);
  451.         }
  452.     }
  453.  
  454.     return err;
  455. }
  456.  
  457.  
  458. /************************************************************
  459.   MyCreateFormatIndexList - This routine stores the index of
  460.   each page's format in a handle.  The index of page #1's
  461.   format will go in the first longword of theFormatIdxList
  462.   handle, the index of the next page's format will go in
  463.   the next longword, and so on.  The handle is created and
  464.   returned to the caller.
  465.  
  466. *************************************************************/
  467.  
  468. OSErr MyCreateFormatIndexList(MyDocumentPtr whichDocument, Handle *theFormatIdxList)
  469. {
  470.     OSErr        err;
  471.     long        fmtIdx, pg, *idxList;
  472.     gxFormat    curFormat;
  473.  
  474. /*
  475.     Create a handle large enough to hold all of our entries.  We use
  476.     NewHandleClear so that all of our indices are initialized to 0
  477.     (an invalid format index).  Since our application stores a nil
  478.     format reference for any page which uses the job's default format,
  479.     this allows us to indicate these "nil references" by an index of
  480.     0 in our collection item.  When we re-open the document, we'll
  481.     know that an index of 0 means "Use the job's default format."
  482. */
  483.     *theFormatIdxList = NewHandleClear(sizeof(long) * (whichDocument->numPages));
  484.     err = MemError();
  485.  
  486. /*
  487.     If there aren't any errors, go through every format in the document's
  488.     job.  If the format is used by any pages of our document, store the
  489.     format's index in those page entries of theFormatIdxList.  We skip
  490.     format #1, since that's the job format (and we're storing nil for the
  491.     index in this case).  Because we created the handle with NewHandleClear,
  492.     nil will already be stored in any entries we don't change.
  493. */
  494.     if (err == noErr)
  495.     {
  496.         HLock(*theFormatIdxList);
  497.         idxList = (long *) **theFormatIdxList;
  498.         
  499.         for (fmtIdx = 2; fmtIdx <= GXCountJobFormats(whichDocument->documentJob); fmtIdx++)
  500.         {
  501.             curFormat = GXGetJobFormat(whichDocument->documentJob, fmtIdx);
  502.     
  503.             for (pg = 1; pg <= whichDocument->numPages; pg++)
  504.                 if (whichDocument->pageFormat[pg -1] == curFormat)
  505.                     idxList[pg -1] = fmtIdx;
  506.         }
  507.         
  508.         HUnlock(*theFormatIdxList);
  509.     }
  510.  
  511.     return err;
  512. }
  513.  
  514.  
  515. /************************************************************
  516.   MyAdjustFormats - This routine associates new format
  517.   references with a document, based upon the format indices
  518.   which were saved with the document.  The routine is called
  519.   when we open a document.
  520.   
  521.   The format references will be stored in the passed
  522.   MyDocumentPtr structure.
  523.  
  524. *************************************************************/
  525.  
  526. OSErr MyAdjustFormats(MyDocumentPtr whichDocument)
  527. {
  528.     OSErr        err = noErr;
  529.     Handle        theFormatIdxList = nil;
  530.     gxFormat    theFormat, defaultFmt;
  531.     long        pg, numPages, fmtIdx, *idxList, idx, listSize, attribs;
  532.     Collection    fmtCollection;
  533.  
  534. /*
  535.     Get the job's default format's collection, and look for one
  536.     of our page-to-format correspondence items in it.
  537. */
  538.     defaultFmt = GXGetJobFormat(whichDocument->documentJob, 1);
  539.     fmtCollection = GXGetFormatCollection(defaultFmt);
  540.  
  541. /*
  542.     Load our item containing our page-to-format correspondences.
  543.     We do this in two passes.  First we determine if the item
  544.     exists, and if so, get its size.  Next we create a handle
  545.     to hold the item (if it exists), and then actually retrieve it.
  546.     Because there will be one longword entry for each page of our
  547.     document, we can determine the number of pages in the document.
  548. */
  549.     err = GetCollectionItemInfo(fmtCollection, kMyFormatInfoType,
  550.                                 kMyFormatInfoTagID, &idx, &listSize, &attribs);
  551.  
  552.     if (err == noErr)
  553.         theFormatIdxList = NewHandle(listSize);
  554.  
  555.     if (theFormatIdxList != nil)
  556.     {
  557.         HLock(theFormatIdxList);
  558.  
  559.         err = GetCollectionItem(fmtCollection, kMyFormatInfoType,
  560.                                   kMyFormatInfoTagID, dontWantSize, *theFormatIdxList);
  561.  
  562.         numPages = listSize / sizeof(long);
  563.  
  564. /*
  565.     Now load the data for our document's pages.  (In this app, we cheat and
  566.     rebuild the pages here, rather than load and save the page data.)
  567. */
  568.         for (pg = 1; (err == noErr) && (pg < numPages); pg++)
  569.         {
  570.             long    newPage = pg -1;
  571.  
  572.             err = MyInsertPage(whichDocument, &newPage);
  573.             whichDocument->curPage = pg;
  574.         }
  575.         whichDocument->curPage = 1;
  576.  
  577.     /* 
  578.         Place your application-specific code here to load 
  579.         page data associated with the document.
  580.         .
  581.         .
  582.         .
  583.     */
  584.  
  585. /*
  586.     Loop through each saved index.  The way we saved them, the first
  587.     is for page 1, the second is for page 2, and so on.  We need to call
  588.     GXGetJobFormat for each saved index.  If the index is nil, that's
  589.     just our way of saying "use the job format."  In that case, we don't
  590.     call GXGetJobFormat, we just store nil for the page's format.  Store
  591.     the format references as they're processed.  When we're done, throw
  592.     away the handle we created.
  593. */
  594.         idxList = (long *) *theFormatIdxList;
  595.         
  596.         for (pg = 0; (err == noErr) && (pg < numPages); pg++)
  597.         {
  598.             fmtIdx = idxList[pg];
  599.             
  600.             if (fmtIdx != (long) nil)
  601.             {
  602.                 theFormat = GXGetJobFormat(whichDocument->documentJob, fmtIdx);
  603.                 err = GXGetJobError(whichDocument->documentJob);
  604.             }
  605.             else
  606.                 theFormat = nil;
  607.  
  608.             if (!err)    
  609.                 whichDocument->pageFormat[pg] = theFormat;
  610.         }
  611.  
  612.         DisposHandle(theFormatIdxList);
  613.     }
  614.  
  615.     return err;
  616. }
  617.  
  618.  
  619. /************************************************************
  620.   MySavePrintInfo - This routine saves our print record or
  621.   gxJob data with the document, so that it can be used the
  622.   next time the document is opened.
  623.  
  624. *************************************************************/
  625.  
  626. OSErr MySavePrintInfo(MyDocumentPtr whichDocument, short resRefNum)
  627. {
  628.     OSErr        err;
  629.     Handle        thePrintData, oldPrintData;
  630.     OSType        dataResType;
  631.     short        dataResID;
  632.  
  633. /*
  634.     If QuickDraw GX is present, flatten the document's gxJob into a
  635.     handle so that we can write it to disk.  Otherwise, make a copy
  636.     of the document's print handle.  In either case, set up the
  637.     resource type and ID to use.  Notice how smoothly this makes
  638.     the rest of the routine work.  We don't need to worry about
  639.     whether we're storing a gxJob or a print record to disk.
  640. */
  641.  
  642.     UseResFile(resRefNum);
  643.  
  644.     if (gGXIsPresent)
  645.     {
  646.         err = MySaveFormatRefs(whichDocument);
  647.         nrequire(err, CouldNotSaveFormatRefs);
  648.  
  649.         thePrintData = NewHandle(0);
  650.         GXFlattenJobToHdl(whichDocument->documentJob, thePrintData);
  651.         err = GXGetJobError(whichDocument->documentJob);
  652.         nrequire(err, CouldNotFlattenJob);
  653.  
  654.         dataResType = kMyJobType;
  655.         dataResID = kMyJobID;
  656.     }
  657.     else
  658.     {
  659.         thePrintData = (Handle) whichDocument->documentPrintHdl;
  660.         err = HandToHand(&thePrintData);
  661.         nrequire(err, CouldNotDuplicatePrintHdl);
  662.  
  663.         dataResType = kMyPrintRecType;
  664.         dataResID = kMyPrintRecID;
  665.     }
  666.  
  667. // If there's an existing resource, delete it.
  668.  
  669.     oldPrintData = Get1Resource(dataResType, dataResID);
  670.  
  671.     if (oldPrintData != nil)
  672.     {
  673.         RmveResource(oldPrintData);
  674.         UpdateResFile(resRefNum);
  675.         DisposHandle(oldPrintData);
  676.     }
  677.  
  678. // Add our new resource.
  679.  
  680.     AddResource(thePrintData, dataResType, dataResID, "\p");
  681.     err = ResError();
  682.     nrequire(err, CouldNotAddResource);
  683.  
  684.     WriteResource(thePrintData);
  685.     UpdateResFile(resRefNum);
  686.     DetachResource(thePrintData);
  687.  
  688. CouldNotAddResource:
  689.     DisposHandle(thePrintData);
  690.  
  691. CouldNotDuplicatePrintHdl:
  692. CouldNotFlattenJob:
  693. CouldNotSaveFormatRefs:
  694.     return err;
  695. }
  696.  
  697.  
  698. /************************************************************
  699.   MyLoadPrintInfo - This routine loads our document's
  700.   previously saved print record or gxJob data.
  701.  
  702. *************************************************************/
  703.  
  704. OSErr MyLoadPrintInfo(MyDocumentPtr whichDocument, short resRefNum)
  705. {
  706.     OSErr        err = noErr;
  707.     THPrint        savedPrintHdl;
  708.     Handle        theJobData = nil;
  709.     
  710.     UseResFile(resRefNum);
  711.  
  712. /*
  713.     If we're using QuickDraw GX, and there's a job resource saved,
  714.     load it and unflatten it.  Any format references saved with a
  715.     document are no longer valid, so we need to adjust them.
  716. */
  717.     if (gGXIsPresent)
  718.     {
  719.         theJobData = Get1Resource(kMyJobType, kMyJobID);
  720.  
  721.         if (theJobData != nil)
  722.         {
  723.             GXUnflattenJobFromHdl(whichDocument->documentJob, theJobData);
  724.             err = GXGetJobError(whichDocument->documentJob);
  725.             ReleaseResource(theJobData);
  726.  
  727.             if (err == noErr)
  728.                 err = MyAdjustFormats(whichDocument);
  729.         }
  730.     }
  731.  
  732. /*
  733.     If there was no job data saved or we're not using QuickDraw GX,
  734.     try to load a previously saved print record.  If we find one,
  735.     and QuickDraw GX is being used, convert the print record to
  736.     a gxJob.  Otherwise, if we find one and QuickDraw GX is not
  737.     being used, dispose of the print handle that we allocated in
  738.     our MyCreateDocument routine.
  739.     
  740.     Note that if no gxJob or print record was previously saved,
  741.     we'll simply end up using the one we created in our
  742.     MyCreateDocument routine.  So, no matter what, we'll always
  743.     have a gxJob or print record to use!
  744. */
  745.     if (theJobData == nil)
  746.     {
  747.         savedPrintHdl = (THPrint) Get1Resource(kMyPrintRecType, kMyPrintRecID);
  748.  
  749.         if (savedPrintHdl != nil)
  750.         {
  751.             DetachResource((Handle) savedPrintHdl);
  752.  
  753.             if (gGXIsPresent)
  754.             {
  755.                 GXConvertPrintRecord(whichDocument->documentJob, savedPrintHdl);
  756.                 DisposeHandle((Handle) savedPrintHdl);
  757.                 err = GXGetJobError(whichDocument->documentJob);
  758.             }
  759.             else
  760.             {
  761.                 DisposHandle((Handle) whichDocument->documentPrintHdl);
  762.                 whichDocument->documentPrintHdl = savedPrintHdl;
  763.             }
  764.         }
  765.     }
  766.     
  767.     return err;
  768. }
  769.  
  770.  
  771.  
  772.  
  773.